import 'dart:io';
import 'dart:convert';

import 'package:ddlmanager/backend/settings.dart';
import 'package:ddlmanager/backend/ddl.dart';
import 'package:ddlmanager/backend/ddl_list.dart';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

class AppState extends ChangeNotifier {
  late final String dataPath;
  late AppSettings settings;
  late DDLlist ddlList;
  late DDLlist ddlListCompleted;

  static final AppState _instance = AppState._internal();
  factory AppState() => _instance;
  AppState._internal() {
    settings = AppSettings();
    ddlList = DDLlist(ddlList: []);
    ddlListCompleted = DDLlist(ddlList: []);
  }

  Future<void> init() async {
    dataPath = (await getApplicationSupportDirectory()).path;
    var version = 'version1.2';
    var isOldVersion = false;
    var fp = File("$dataPath/config/version");
    if (!await fp.exists()) {
      await fp.create(recursive: true);
      await fp.writeAsString(version);
      isOldVersion = true;
    }
    var versionStr = await fp.readAsString();
    if (versionStr != version) {
      await fp.writeAsString(version);
      isOldVersion = true;
    }
    print('isOldVersion: $isOldVersion');
    await loadSettings(isOldVersion);
    await loadDDLlist(isOldVersion);
  }

  Future<void> loadSettings(bool isOldVersion) async {
    var settingsPath = "$dataPath/config/settings.json";
    var fp = File(settingsPath);
    if (!await fp.exists()) {
      await fp.create(recursive: true);
      var data = AppSettings().toJson();
      var str = jsonEncode(data);
      await fp.writeAsString(str);
    }
    if (isOldVersion) {
      var data = AppSettings().toJson();
      var str = jsonEncode(data);
      await fp.writeAsString(str);
    }
    settings = AppSettings.fromJson(jsonDecode(await fp.readAsString()));
  }

  Future<void> saveSettings() async {
    var settingsPath = "$dataPath/config/settings.json";
    var fp = File(settingsPath);
    var data = settings.toJson();
    var str = jsonEncode(data);
    await fp.writeAsString(str);
  }

  Future<void> loadDDLlist(bool isOldVersion) async {
    var listPath = "$dataPath/data/ddl_list.json";
    var fp = File(listPath);
    if (!await fp.exists()) {
      await fp.create(recursive: true);
      var data = ddlList.toJson();
      var str = jsonEncode(data);
      await fp.writeAsString(str);
    }
    ddlList = DDLlist.fromJson(jsonDecode(await fp.readAsString()));

    listPath = "$dataPath/data/ddl_list_completed.json";
    fp = File(listPath);
    if (!await fp.exists()) {
      await fp.create(recursive: true);
      var data = ddlListCompleted.toJson();
      var str = jsonEncode(data);
      await fp.writeAsString(str);
    }
    ddlListCompleted = DDLlist.fromJson(jsonDecode(await fp.readAsString()));

    if (isOldVersion) {
      for (int i = 0; i < ddlList.ddlList.length; i++) {
        if (ddlList.ddlList[i].isCompleted == true) {
          ddlListCompleted.ddlList.add(ddlList.ddlList[i]);
        }
      }
      ddlList.ddlList.removeWhere((ddl) => ddl.isCompleted == true);
      saveDDLlist();
    }
  }

  Future<void> saveDDLlist() async {
    var listPath = "$dataPath/data/ddl_list.json";
    var fp = File(listPath);
    var data = ddlList.toJson();
    var str = jsonEncode(data);
    await fp.writeAsString(str);

    listPath = "$dataPath/data/ddl_list_completed.json";
    fp = File(listPath);
    data = ddlListCompleted.toJson();
    str = jsonEncode(data);
    await fp.writeAsString(str);
  }

  void addDDL(DDL ddl) {
    ddlList.ddlList.add(ddl);
    saveDDLlist();
    notifyListeners();
  }

  void deleteDDL(int index) {
    ddlList.ddlList.removeAt(index);
    saveDDLlist();
    notifyListeners();
  }

  void completeDDL(int index) {
    ddlList.ddlList[index].isCompleted = true;
    ddlList.ddlList[index].completionDate = DateTime.now();
    ddlList.ddlList[index].updateDate = DateTime.now();
    ddlListCompleted.ddlList.add(ddlList.ddlList[index]);
    ddlList.ddlList.removeAt(index);

    saveDDLlist();
    notifyListeners();
  }

  void restoreCompletedDDL(int index) {
    ddlListCompleted.ddlList[index].isCompleted = false;
    ddlListCompleted.ddlList[index].updateDate = DateTime.now();
    ddlList.ddlList.add(ddlListCompleted.ddlList[index]);
    ddlListCompleted.ddlList.removeAt(index);
    saveDDLlist();
    notifyListeners();
  }

  void deleteCompletedDDL(int index) {
    ddlListCompleted.ddlList.removeAt(index);
    saveDDLlist();
    notifyListeners();
  }

  void updateDDL(int index, DDL updatedDDL) {
    ddlList.ddlList[index] = updatedDDL;
    saveDDLlist();
    notifyListeners();
  }

  void sortByDeadline(bool isddlList) {
    if (isddlList) {
      ddlList.ddlList.sort((a, b) => a.deadline.compareTo(b.deadline));
    } else {
      ddlListCompleted.ddlList.sort((a, b) => a.deadline.compareTo(b.deadline));
    }
    saveDDLlist();
    notifyListeners();
  }

  void sortByTitle(bool isddlList) {
    if (isddlList) {
      ddlList.ddlList.sort((a, b) => a.title.compareTo(b.title));
    } else {
      ddlListCompleted.ddlList.sort((a, b) => a.title.compareTo(b.title));
    }
    saveDDLlist();
    notifyListeners();
  }

  void sortByUpdateTime(bool isddlList) {
    if (isddlList) {
      ddlList.ddlList.sort((b, a) => a.updateDate.compareTo(b.updateDate));
    } else {
      ddlListCompleted.ddlList.sort(
        (b, a) => a.completionDate.compareTo(b.completionDate),
      );
    }
    saveDDLlist();
    notifyListeners();
  }

  void sortByCompletionDate() {
    ddlListCompleted.ddlList.sort(
      (b, a) => a.completionDate.compareTo(b.completionDate),
    );
    saveDDLlist();
    notifyListeners();
  }

  void sortByPriority(bool isddlList) {
    if (isddlList) {
      ddlList.ddlList.sort((a, b) => a.priority.compareTo(b.priority));
    } else {
      ddlListCompleted.ddlList.sort((a, b) => a.priority.compareTo(b.priority));
    }
    saveDDLlist();
    notifyListeners();
  }

  void setThemeCode(int index) {
    settings.themeCode = index;
    saveSettings();
    notifyListeners();
  }

  void setThemeMode(ThemeMode value) {
    settings.themeMode = value;
    saveSettings();
    notifyListeners();
  }
}
